/************************************************************************

								Heroes IV
					  Copyright 2001, The 3DO Company

	------------------------------------------------------------------
  						       dialog_caravan_view.cpp

	$Header: $

	$NoKeywords: $

 ************************************************************************/

// kill the 255+ character identifier warning.  Templates tend to exceed that easily.
#include "precompiled.h"
#pragma warning( disable: 4786 )

#include "dialog_caravan_view.h"

#include "adaptor_handler.h"
#include "adventure_map.h"
#include "bitmap_layer_window.h"
#include "bitmap_group.h"
#include "bitmap_group_cache.h"
#include "bound_handler.h"
#include "button.h"
#include "button_cache.h"
#include "caravan.h"
#include "caravan_set.h"
#include "creature_info_window.h"
#include "external_string.h"
#include "format_string.h"
#include "interface_help.h"
#include "keyword_replacer.h"
#include "minimum_maximum.h"
#include "player.h"
#include "player_color.h"
#include "replace_keywords.h"
#include "scrollbar.h"
#include "simple_dialog.h"
#include "standard_fonts.h"
#include "text_window.h"
#include "town.h"
#include "town_list.h"
#include "town_list_ptr.h"

extern t_button_cache			g_ok_button;
extern t_bitmap_group_cache     g_banners_55;

namespace
{
	t_external_string const k_no_caravans_global( "caravan_view.no_caravans_global" );
	t_external_string const k_no_caravans_town( "caravan_view.no_caravans_town" );
	t_external_string const k_title_global( "caravan_view.title_global" );
	t_external_string const k_title_town( "caravan_view.title_town" );
	t_external_string const k_day_subtext( "caravan_view.day_subtext" );
	t_external_string const k_days_subtext( "caravan_view.days_subtext" );
	t_external_string const k_days_help_balloon( "caravan_view.days_help_balloon" );
	t_external_string const k_days_right_click( "caravan_view.days_right_click" );
	t_external_string const k_today_text( "caravan_view.today_text" );
	t_external_string const k_today_right_click( "caravan_view.today_right_click" );
	t_external_string const k_arrived_text( "caravan_view.arrived_text" );
	t_external_string const k_arrived_right_click( "caravan_view.arrived_right_click" );
	t_external_string const k_location_self( "caravan_view.location_self" );
	t_external_string const k_location_other( "caravan_view.location_other" );
	t_bitmap_group_cache const k_bitmaps( "dialog.caravan_view" );

	int const k_day_text_days_font_size = 36;
	int const k_day_text_other_font_size = 14;
};

// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
t_dialog_caravan_view::t_dialog_caravan_view( t_window * parent, t_adventure_map & map )
	: t_window( k_completely_transparent, parent ),
	  m_map( map )
{
}

// ---------------------------------------------------------------------------
// Set up dialog. Proceed only if function returns true
// If town is NULL, all caravans known to the player will display. If not NULL,
// only caravans with a destination of the given town will display
// ---------------------------------------------------------------------------
bool t_dialog_caravan_view::init_dialog( t_town * town )
{
	t_keyword_replacer town_replacer;

	// Construct dialog list
	if ( town )
	{
		add_caravans_for_town( town, -1000 );
		town_replacer.add_keyword( "%town", town->get_name() );
	}
	else
	{
		int player_number = m_map.get_player_number();
		t_player & player = m_map.get_player();

		t_caravan_set const & caravans = player.get_caravans();

		t_caravan_set::const_iterator caravan_iter;

		for ( caravan_iter = caravans.begin(); caravan_iter != caravans.end(); caravan_iter++ )
		{
			m_caravans.push_back( caravan_iter->get() );
		}

		// Also get any enemy caravans approaching towns the player owns
		t_town_list_ptr towns = player.get_towns();
		t_town_list::iterator town_iter;

		for ( town_iter = towns->begin(); town_iter != towns->end(); town_iter++ )
		{
			add_caravans_for_town( *town_iter, player_number );
		}
	}

	if ( m_caravans.empty() )
	{
		if ( town )
		{
			ok_dialog( town_replacer( k_no_caravans_town ), true );
		}
		else
		{
			ok_dialog( k_no_caravans_global, true );
		}

		return false;
	}

	// Create subwindows
	m_bitmaps = k_bitmaps.get();
	m_flag_bitmaps_ptr = g_banners_55.get();
	t_help_block const& help = get_help_block( "caravan_view" );

	t_bitmap_layer const * layer;
	t_bitmap_layer_window *background;
	t_text_window *		   text_window;
	t_button *             button;

	layer = m_bitmaps->find( "background" );
	background = new t_bitmap_layer_window( layer, t_screen_point(0, 0), this );

	layer = m_bitmaps->find( "title scroll" );
	new t_bitmap_layer_window( layer, t_screen_point(0, 0), background );

	std::string title;
	if ( town )
	{
		title = town_replacer( k_title_town );
	}
	else
	{
		title = k_title_global;
	}

	layer = m_bitmaps->find( "title" );
	text_window = new t_text_window( get_font( 20 ), layer->get_rect(), background, title, t_pixel_24(0,0,0) );
	text_window->set_drop_shadow( false );
	text_window->set_justification( k_justify_center );

	if ( m_caravans.size() > k_displayed_caravans )
	{
		// Add scrollbar
		layer = m_bitmaps->find( "scrollbar" );
		t_scrollbar * scrollbar = new t_scrollbar( layer->get_rect().top_left(), layer->get_rect().height(),
												   background, 0, m_caravans.size() - k_displayed_caravans );

		scrollbar->set_handler( bound_handler( *this, &t_dialog_caravan_view::scroll ) );
		scrollbar->set_page_size( k_displayed_caravans );
	}

	layer = m_bitmaps->find( "close_button" );
	button = new t_button( g_ok_button.get(), layer->get_rect().top_left(), background );
	button->set_click_handler( bound_handler( *this, &t_dialog_caravan_view::close_clicked ) );
	set_help( text_window, help, "close" );

	// Set up caravan displays
	m_first_visible_caravan = 0;
	int visible_caravans = minimum( unsigned int( k_displayed_caravans ), m_caravans.size() );
	int i;

	layer = m_bitmaps->find( "caravan_1" );
	t_screen_point caravan_1_position = layer->get_rect().top_left();

	layer = m_bitmaps->find( "flag_1" );
	t_screen_point flag_offset = layer->get_rect().top_left() - caravan_1_position;

	layer = m_bitmaps->find( "days_text" );
	t_screen_rect days_offset = layer->get_rect() - caravan_1_position;

	layer = m_bitmaps->find( "days_subtext" );
	t_screen_rect days_subtext_offset = layer->get_rect() - caravan_1_position;

	layer = m_bitmaps->find( "caravan_rings" );
	t_screen_point rings_offset = layer->get_rect().top_left() - caravan_1_position;

	layer = m_bitmaps->find( "location" );
	t_screen_rect location_offset = layer->get_rect() - caravan_1_position;

	t_bitmap_layer const * days_background_layer = m_bitmaps->find( "days_background" );
	t_bitmap_layer const * number_background_layer = m_bitmaps->find( "number_background" );
	t_bitmap_layer const * rings_background_layer = m_bitmaps->find( "rings_background" );
	t_bitmap_layer const * location_background_layer = m_bitmaps->find( "location_scroll" );

	for ( i = 0; i < visible_caravans; i++ )
	{
		t_screen_point position;

		if ( i == 0 )
		{
			position = caravan_1_position;
		}
		else
		{
			layer = m_bitmaps->find( format_string( "caravan_%d", i + 1 ) );
			position = layer->get_rect().top_left();
		}

		t_screen_point diff = position - caravan_1_position;

		new t_bitmap_layer_window( days_background_layer, diff, background );
		new t_bitmap_layer_window( number_background_layer, diff, background );
		new t_bitmap_layer_window( rings_background_layer, diff, background );
		new t_bitmap_layer_window( location_background_layer, diff, background );

		m_visible_caravans[i].m_flag = new t_bitmap_layer_window( NULL, position + flag_offset, background );
		set_help( m_visible_caravans[i].m_flag, help, "flag" );
		m_visible_caravans[i].m_days = new t_text_window( get_font( 16 ), position + days_offset, background, "", t_pixel_24( 0, 0, 0 ) );
		m_visible_caravans[i].m_days->set_drop_shadow( false );
		m_visible_caravans[i].m_days->set_justification( k_justify_center );
		m_visible_caravans[i].m_days->set_help_balloon_text( k_days_help_balloon );

		m_visible_caravans[i].m_days_subtext = new t_text_window( get_font( 12 ), position + days_subtext_offset, background, "", t_pixel_24( 0, 0, 0 ) );
		m_visible_caravans[i].m_days_subtext->set_drop_shadow( false );
		m_visible_caravans[i].m_days_subtext->set_justification( k_justify_center );
		m_visible_caravans[i].m_days_subtext->set_right_click_text( k_days_right_click );
		m_visible_caravans[i].m_days_subtext->set_help_balloon_text( k_days_help_balloon );
		
		m_visible_caravans[i].m_location = new t_text_window( get_font( 16 ), position + location_offset, background, "", t_pixel_24( 0, 0, 0 ) );
		m_visible_caravans[i].m_location->set_drop_shadow( false );
		m_visible_caravans[i].m_location->set_justification( k_justify_center );
		set_help( m_visible_caravans[i].m_location, help, "location" );
		
		m_visible_caravans[i].m_creatures = new t_creature_info_window( position + rings_offset, NULL, k_skill_mastery_count, t_creature_info_window::k_single_row, background );
		t_creature_info_handler handler =  add_3rd_argument( bound_handler( *this, &t_dialog_caravan_view::selection_changed ), i );
		m_visible_caravans[i].m_creatures->set_select_handler( handler );

		update_visible( i );
	}

	t_screen_rect rect = m_bitmaps->get_rect();
	rect += (get_parent()->get_client_rect().size() - rect.size()) / 2;
	init( rect );

	return true;
}

// ---------------------------------------------------------------------------
// Add all the caravans with the given town as a destination to m_caravans. If 
// ignore_player_number is a valid player number, caravans owned by that player
// will not be added
// ---------------------------------------------------------------------------
void t_dialog_caravan_view::add_caravans_for_town( t_town * town, int ignore_player_number )
{
	t_caravan_set::iterator cur = m_map.get_caravans().get_lower_bound_of_destination( town );
	t_caravan_set::iterator end = m_map.get_caravans().end();

	while ( cur != end && (*cur)->get_destination().get() == town )
	{
		if ( (*cur)->get_owner_number() != ignore_player_number )
		{
			m_caravans.push_back( *cur );
		}
		cur++;
	}
}

// ---------------------------------------------------------------------------
// Handle click of the close button
// ---------------------------------------------------------------------------
void t_dialog_caravan_view::close_clicked( t_button * )
{
	close();
}

// ---------------------------------------------------------------------------
// Handle scroll bar change
// ---------------------------------------------------------------------------
void t_dialog_caravan_view::scroll( t_scrollbar *, int position )
{
	assert( m_caravans.size() < k_displayed_caravans || position + k_displayed_caravans <= m_caravans.size() );

	m_first_visible_caravan = position;
	int visible_caravans = minimum( unsigned int( k_displayed_caravans ), m_caravans.size() );
	int i;

	for ( i = 0; i < visible_caravans; i++ )
	{
		update_visible( i );
	}
}


// ---------------------------------------------------------------------------
// Handle a selection of one of the visible creatures
// ---------------------------------------------------------------------------
void t_dialog_caravan_view::selection_changed( t_creature_info_window *, int selected_creature, int visible_index )
{
	if ( selected_creature == -1 )
		return;

	int i;

	for ( i = 0; i < k_displayed_caravans; i++ )
	{
		if ( i != visible_index && m_visible_caravans[i].m_creatures.get() != NULL )
		{
			m_visible_caravans[i].m_creatures->select_creature( -1 );
		}
	}
}

// ---------------------------------------------------------------------------
// Update the windows in m_visible_caravans[visible_index]
// ---------------------------------------------------------------------------
void t_dialog_caravan_view::update_visible( int visible_index )
{
	int caravan_index = visible_index + m_first_visible_caravan;

	assert( caravan_index < m_caravans.size() );

	if ( m_visible_caravans[visible_index].m_creatures.get() == NULL )
		return; // Still initializing

	t_caravan const & caravan = *m_caravans[caravan_index];

	int player_number = caravan.get_owner_number();
	t_player & player = *caravan.get_owner();

    t_bitmap_layer const * layer;
	
	layer = m_flag_bitmaps_ptr->find( k_player_color_keyword[ player.get_color() ] );
	m_visible_caravans[visible_index].m_flag->set_bitmap( layer, true );

	m_visible_caravans[visible_index].m_creatures->set_army( &caravan );

	if ( same_team( &player, &m_map.get_player() ) )
	{
		m_visible_caravans[visible_index].m_creatures->set_scouting_level( k_skill_mastery_count );
		m_visible_caravans[visible_index].m_location->set_text( replace_keywords( k_location_self,
																				  "%origin", caravan.get_origin_name(),
																				  "%destination", caravan.get_destination()->get_name() ) );
	}
	else
	{
		m_visible_caravans[visible_index].m_creatures->set_scouting_level( k_mastery_none );
		m_visible_caravans[visible_index].m_location->set_text( replace_keywords( k_location_other,
																				  "%destination", caravan.get_destination()->get_name() ) );
	}

	if ( caravan.has_arrived() )
	{
		m_visible_caravans[visible_index].m_days->set_font( get_font( k_day_text_other_font_size ) );
		m_visible_caravans[visible_index].m_days->set_text( k_arrived_text );
		m_visible_caravans[visible_index].m_days->set_right_click_text( k_arrived_right_click );
		m_visible_caravans[visible_index].m_days_subtext->set_visible( false );
	}
	else
	{
		int days_to_arrival = caravan.get_arrival_day() - m_map.get_day();

		if ( days_to_arrival == 0 )
		{
			m_visible_caravans[visible_index].m_days->set_font( get_font( k_day_text_other_font_size ) );
			m_visible_caravans[visible_index].m_days->set_text( k_today_text );
			m_visible_caravans[visible_index].m_days->set_right_click_text( k_today_right_click );
			m_visible_caravans[visible_index].m_days_subtext->set_visible( false );
		}
		else 
		{
			m_visible_caravans[visible_index].m_days->set_font( get_font( k_day_text_days_font_size ) );
			m_visible_caravans[visible_index].m_days->set_text( format_string( "%d", days_to_arrival ) );
			m_visible_caravans[visible_index].m_days->set_right_click_text( k_days_right_click );
			m_visible_caravans[visible_index].m_days_subtext->set_visible( true );

			if ( days_to_arrival == 1 ) 
			{
				m_visible_caravans[visible_index].m_days_subtext->set_text( k_day_subtext );
			}
			else
			{
				m_visible_caravans[visible_index].m_days_subtext->set_text( k_days_subtext );
			}
		}
	}
}
